#include "RenderTexture.h"
#include "Device.h"

using namespace Graphics;

RenderTexture::RenderTexture(void)
	:mRenderTargetTexture(NULL),
	 mRenderTargetView(NULL),
	 mShaderResourceView(NULL)
{
}

RenderTexture::~RenderTexture(void)
{
}

bool RenderTexture::Initialize(int textureWidth, int textureHeight)
{
	Graphics::D3DDevice* nDevice = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();
	mTextureWidth = textureWidth;
	mTextureHeight = textureHeight;

	bool result;

	result = SetupRenderTargetTexture(nDevice);
	result = SetupRenderTargetView(nDevice);
	result = SetupShaderResourceView(nDevice);
	
	return result;
}

bool RenderTexture::SetupRenderTargetTexture(D3DDevice* device)
{
	D3D11_TEXTURE2D_DESC textureDesc;
	// Initialize the render target texture description.
	ZeroMemory(&textureDesc, sizeof(textureDesc));

	// Setup the render target texture description.
	textureDesc.Width					= mTextureWidth;
	textureDesc.Height					= mTextureHeight;
	textureDesc.MipLevels				= 1;
	textureDesc.ArraySize				= 1;
	textureDesc.Format					= DXGI_FORMAT_R32G32B32A32_FLOAT;
	textureDesc.SampleDesc.Count		= 1;
	textureDesc.Usage					= D3D11_USAGE_DEFAULT;
	textureDesc.BindFlags				= D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	textureDesc.CPUAccessFlags			= 0;
	textureDesc.MiscFlags				= 0;

	// Create the render target texture.
	HRESULT result = device->GetDevice()->CreateTexture2D(&textureDesc, NULL, &mRenderTargetTexture);
	CHECK(result);
	return true;
}

bool RenderTexture::SetupRenderTargetView(D3DDevice* device)
{
	D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
	// Setup the description of the render target view.
	renderTargetViewDesc.Format					= DXGI_FORMAT_R32G32B32A32_FLOAT;
	renderTargetViewDesc.ViewDimension			= D3D11_RTV_DIMENSION_TEXTURE2D;
	renderTargetViewDesc.Texture2D.MipSlice		= 0;

	// Create the render target view.
	HRESULT result = device->GetDevice()->CreateRenderTargetView(mRenderTargetTexture, &renderTargetViewDesc, &mRenderTargetView);
	CHECK(result);
	return true;
}

bool RenderTexture::SetupShaderResourceView(D3DDevice* device)
{
	D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
	// Setup the description of the shader resource view.
	shaderResourceViewDesc.Format						= DXGI_FORMAT_R32G32B32A32_FLOAT;
	shaderResourceViewDesc.ViewDimension				= D3D11_SRV_DIMENSION_TEXTURE2D;
	shaderResourceViewDesc.Texture2D.MostDetailedMip	= 0;
	shaderResourceViewDesc.Texture2D.MipLevels			= 1;

	// Create the shader resource view.
	HRESULT result = device->GetDevice()->CreateShaderResourceView(mRenderTargetTexture, &shaderResourceViewDesc, &mShaderResourceView);
	CHECK(result);
	return true;
}

void RenderTexture::Deinitialize()
{
	if(mShaderResourceView)
	{
		mShaderResourceView->Release();
		mShaderResourceView = NULL;
	}

	if(mRenderTargetView)
	{
		mRenderTargetView->Release();
		mRenderTargetView = NULL;
	}

	if(mRenderTargetTexture)
	{
		mRenderTargetTexture->Release();
		mRenderTargetTexture = NULL;
	}

}

void RenderTexture::SetRenderTarget()
{
	Graphics::D3DDevice* nDevice = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();
	// Bind the render target view and depth stencil buffer to the output render pipeline.
	nDevice->GetDeviceContext()->OMSetRenderTargets(1, &mRenderTargetView, nDevice->GetDepthStencilView());
}

void RenderTexture::ClearRenderTarget(Color color)
{
	Graphics::D3DDevice* nDevice = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();

	// Clear the back buffer.
	nDevice->GetDeviceContext()->ClearRenderTargetView(mRenderTargetView, color.FColor);
    
	// Clear the depth buffer.
	nDevice->GetDeviceContext()->ClearDepthStencilView(nDevice->GetDepthStencilView(), D3D11_CLEAR_DEPTH, 1.0f, 0);
}

ID3D11ShaderResourceView* RenderTexture::GetShaderResourceView()
{
	return mShaderResourceView;
}